package cn.zk.base;

import org.apache.log4j.Logger;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;
import java.util.List;
import java.util.Objects;

/**
 * ClassName: ZkClientFirst
 * Desc: 原生客户端学习
 * Date： 2016/12/2
 * Created：shaom
 */
public class ZkClientFirst {

    private static final Logger logger = Logger.getLogger(ZkClientFirst.class);
    private static final String zkHost = "master:2181,slave01:2181,slave02:2181";//服务地址
    private static ZooKeeper zkClient = null;


    public ZkClientFirst() {
        /**
         * 创建一个与服务器的连接 需要(服务端ip+端口号)(session过期时间)(Watcher监听注册)
         */
        try {
            zkClient = new ZooKeeper(zkHost, 3000, new Watcher() {
                // 监控所有被触发的事件
                public void process(WatchedEvent event) {
                    System.out.println("状态 ： " + event.getState());
                    System.out.println("path : " + event.getPath());
                    System.out.println("已经触发了 " + event.getType() + " 事件！");
                }
            });
        } catch (IOException e) {
        }
    }


    /**
     * CreateMode:新建节点：节点属性
     * PERSISTENT ：持续的，相对于EPHEMERAL，不会随着client的断开而消失
     * PERSISTENT_SEQUENTIAL：持久的且带顺序的
     * EPHEMERAL ：短暂的，生命周期依赖于client session
     * EPHEMERAL_SEQUENTIAL  ：短暂的，带顺序的
     */
    void createNode() throws Exception {
        // Path must start with / character
        // 每次都会调用 process 方法
        zkClient.create("/testNode2", "testValue".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    }

    /**
     * 判断节点是否存在
     *
     * @param node
     * @throws Exception
     */
    void exists(String node) throws Exception {
        // 也会触发 process方法
        Stat exists = zkClient.exists(node, true);
        if (!Objects.isNull(exists)) {
            System.out.println(exists);
        }

        // 不会触发 process方法
        zkClient.exists(node, false);
    }

    /**
     * 创建子节点
     *
     * @throws Exception
     */
    void createChild() throws Exception {
        zkClient.create("/testNode/childNode", "childValue".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    }


    void getChildNodes() throws Exception {
        List<String> children = zkClient.getChildren("/", null);
        System.out.println(children);// [zookeeper, hbase, testNode]
    }

    /**
     * 获取节点的值
     *
     * @throws Exception
     */
    void getData() throws Exception {
        byte[] data = zkClient.getData("/testNode", true, null);
        System.out.println(new String(data));//testValue
    }

    /**
     * 修改节点数据
     *
     * @throws KeeperException
     * @throws InterruptedException
     */
    void setNode() throws KeeperException, InterruptedException {
        // 修改节点数据
        System.out.println(new String(zkClient.getData("/testNode", true, null)));
        zkClient.setData("/testNode", "changeChild".getBytes(), -1);
        System.out.println(new String(zkClient.getData("/testNode", true, null)));
    }

    /**
     * 删除节点
     * Directory not empty for /testNode 不能删除非空的节点
     *
     * @throws Exception
     */
    void delete() throws Exception {

        //删除整个子目录   -1代表version版本号，-1是删除所有版本
        zkClient.delete("/testNode/childNode", -1);
        zkClient.delete("/testNode", -1);
    }


}
